/*
 * H264FileReader.cpp
 *
 *  Created: 2012-05-10
 *   Author: terry
 */

#include "stdafx.h"
#include "H264FileReader.h"

#include "Ffmpeg.h"


struct H264FileReader::Pimpl
{
    AVFormatContext*    pFormatCtx;
    AVPacket    packet;

    Pimpl():
        pFormatCtx()
    {
        av_init_packet(&packet);
        packet.data = NULL;
        packet.size = 0;
    }

    void close()
    {
        freePacket();

        if (pFormatCtx)
        {
			avformat_close_input(&pFormatCtx);
            pFormatCtx = NULL;
        }
    }

    void freePacket()
    {
        if (packet.data != NULL)
        {
            av_free_packet(&packet);
            packet.data = 0;
            packet.size = 0;
        }
    }
    
    AVStream* getStream()
    {
        return pFormatCtx->streams[0];
    }

};


H264FileReader::H264FileReader():
    m_pPimpl(new Pimpl()),
    m_duration(),
    m_pos()
{

}

H264FileReader::~H264FileReader()
{
    delete m_pPimpl;
}

bool H264FileReader::open(const char* filename)
{
    int ret = avformat_open_input(&m_pPimpl->pFormatCtx, filename, NULL, NULL);
    if (ret != 0)
    {
        return false;
    }

	avformat_find_stream_info(m_pPimpl->pFormatCtx, NULL);

    if (m_pPimpl->pFormatCtx->nb_streams <= 0)
    {
        m_pPimpl->close();
        return false;
    }

    AVStream* pStream = m_pPimpl->getStream();

    if (pStream->duration != (int64_t)AV_NOPTS_VALUE)
    {
        double scale = av_q2d(pStream->time_base) * 1000;
        m_duration = (long)(pStream->duration * scale);
    }
    else
    {
        
    }

    m_duration = m_pPimpl->pFormatCtx->duration;

    return true;
}

void H264FileReader::close()
{
    m_pPimpl->close();
}

bool H264FileReader::isOpen()
{
    return (m_pPimpl->pFormatCtx != NULL);
}

bool H264FileReader::getPropSet(std::string& sps, std::string& pps)
{
    return false;
}

bool H264FileReader::read(H264NaluPacket& nalu)
{
    m_pPimpl->freePacket();

    int ret = av_read_frame(m_pPimpl->pFormatCtx, &m_pPimpl->packet);
    if (ret < 0)
    {
        return false;
    }

    nalu.data = m_pPimpl->packet.data;
    nalu.length = m_pPimpl->packet.size;

    m_pos += nalu.length;

    return true;
}

long H264FileReader::getTotal()
{
    return m_duration;
}

long H264FileReader::getPos()
{
    return m_pos;
}

bool H264FileReader::setPos(long pos)
{
    bool done = false;
    int ret = av_seek_frame(m_pPimpl->pFormatCtx, 0, pos, AVSEEK_FLAG_BYTE);
    if (ret >= 0)
    {
        m_pos = pos;
        done = true;
    }
    return done;
}